package com.njmd.mdbs.web.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hibernate.criterion.Order;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.njmd.framework.base.BaseCrudServiceImpl;
import com.njmd.framework.dao.BaseHibernateDAO;
import com.njmd.framework.dao.Page;
import com.njmd.framework.dao.PropertyFilter;
import com.njmd.framework.dao.PropertyFilter.MatchType;
import com.njmd.framework.utils.web.WebContextHolder;
import com.njmd.mdbs.web.constants.CommonConstants;
import com.njmd.mdbs.web.constants.ResultConstants;
import com.njmd.mdbs.web.dao.SysLoginRoleDAO;
import com.njmd.mdbs.web.dao.SysRoleDAO;
import com.njmd.mdbs.web.dao.SysRolePermissionDAO;
import com.njmd.mdbs.web.entity.sys.SysLogin;
import com.njmd.mdbs.web.entity.sys.SysLoginRole;
import com.njmd.mdbs.web.entity.sys.SysPermission;
import com.njmd.mdbs.web.entity.sys.SysRole;
import com.njmd.mdbs.web.entity.sys.SysRolePermission;
import com.njmd.mdbs.web.security.LoginToken;
import com.njmd.mdbs.web.service.SysRoleService;

/**
 * 角色管理
 * 
 * @author: sunqw
 * @since 2013.10.12
 */
@Service
public class SysRoleServiceImpl extends BaseCrudServiceImpl<SysRole, Long> implements SysRoleService
{
	/**
	 * 角色信息数据访问对象
	 */
	@Autowired
	private SysRoleDAO sysRoleDAO;

	@Autowired
	private SysLoginRoleDAO sysLoginRoleDAO;

	/**
	 * 角色权限关系信息数据访问对象
	 */
	@Autowired
	private SysRolePermissionDAO sysRolePermissionDAO;

	/**
	 * 保存角色信息
	 * 
	 * @param sysRole
	 *            　角色信息数据传输对象
	 * @return　保存成功或失败
	 * 
	 * 
	 * @throws Exception
	 */
	@Override
	@Transactional(readOnly = false, rollbackFor = Throwable.class)
	public int save(SysRole sysRole) throws Exception
	{
		LoginToken loginToken = WebContextHolder.getCurrLoginToken();
		if (loginToken.getCorpInfo() != null)
			sysRole.setCorpId(loginToken.getCorpInfo().getCorpId());
		else
			sysRole.setCorpId(CommonConstants.NO_PARENT_ID);
		
		if (loginToken.getLoginInfo().getLoginId().longValue() != 0)
		{
			sysRole.setSystemId(loginToken.getLoginInfo().getSystemId());
		}

		List<Long> list = (List<Long>) baseDao.findByHql("select max(model.roleId)+1 from SysRole as model");
		int order = 1;
		if (null != list && list.size() > 0 && null != list.get(0))
		{
			order = list.get(0).intValue();
		}

		// 判断是否已经存在同名角色
		if (sysRoleDAO.findUnique("roleName", sysRole.getRoleName()) == null)
		{
			String permissionIds = sysRole.getPermissionIds();

			sysRole.setOrder(order);

			// 保存角色信息
			sysRoleDAO.save(sysRole);

			// 保存角色菜单
			saveRoleMenu(permissionIds, sysRole);

			return ResultConstants.SAVE_SUCCEED;
		}
		return ResultConstants.SAVE_FAILED_NAME_IS_EXIST;
	}

	/**
	 * 根据角色ID删除角色信息
	 * 
	 * @param roleId
	 *            　角色ID
	 * @return　删除成功或失败
	 * 
	 * 
	 * @throws Exception
	 */
	@Override
	@Transactional(readOnly = false, rollbackFor = Throwable.class)
	public int delete(Long roleId) throws Exception
	{
		// 有用户引用的角色不能被删除
		Long[] roleIds = new Long[1];
		roleIds[0] = roleId;
		if (this.validationRole(roleIds))
		{
			// 删除角色信息
			sysRolePermissionDAO.deleteByRoleId(roleId);
			SysRole sysRole = sysRoleDAO.findById(roleId);
			sysRoleDAO.delete(sysRole);

			return ResultConstants.DELETE_SUCCEED;
		}
		else
			return ResultConstants.DELETE_FAILED_IS_REF;
	}

	/**
	 * 按照条件分页查询角色信息
	 * 
	 * @param page
	 *            　分页信息
	 * @param filters
	 *            　过滤条件列表
	 * @return　角色信息集合
	 * @throws Exception
	 */
	@Override
	public Page query(Page page, List<PropertyFilter> filters) throws Exception
	{
		LoginToken loginToken = WebContextHolder.getCurrLoginToken();
		if (loginToken.getLoginInfo().getSystemId() != 0)
		{
			filters.add(new PropertyFilter("systemId", MatchType.EQ, loginToken.getLoginInfo().getSystemId()));
		}
		Page pageResult = sysRoleDAO.findByPage(page, filters);
		return pageResult;
	}

	/**
	 * 验证角色是否被用户引用，被引用返回true，否则返回false
	 * 
	 * @param roleId
	 *            角色ID
	 * @return
	 * @throws Exception
	 */
	private boolean validationRole(Long[] roleId) throws Exception
	{
		return sysLoginRoleDAO.findLoginByRole(roleId);
	}

	/**
	 * 批量删除角色信息
	 * 
	 * @param roleId
	 *            　角色ID集合
	 * @return 删除成功或失败
	 * 
	 * 
	 * @throws Exception
	 */
	@Override
	@Transactional(readOnly = false, rollbackFor = Throwable.class)
	public int delete(Long[] roleIds) throws Exception
	{
		boolean bool = validationRole(roleIds);
		// 判断是否有角色被用户引用
		if (bool)
		{
			for (Long roleId : roleIds)
			{
				// 删除角色信息
				sysRolePermissionDAO.deleteByRoleId(roleId);
				SysRole sysRole = sysRoleDAO.findById(roleId);
				sysRoleDAO.delete(sysRole);
			}
			return ResultConstants.DELETE_SUCCEED;
		}
		return ResultConstants.DELETE_FAILED_IS_REF;
	}

	/**
	 * 角色信息修改
	 * 
	 * @param sysRole
	 *            　角色信息数据传输对象
	 * @return
	 * @throws Exception
	 */
	@Override
	@Transactional(readOnly = false, rollbackFor = Throwable.class)
	public int update(SysRole sysRole) throws Exception
	{
		// 修改后的角色名是否跟原有的角色名存在重复
		SysRole sysRoleTemp = sysRoleDAO.findUnique("roleName", sysRole.getRoleName());

		if ((sysRoleTemp != null) && (sysRoleTemp.getRoleId().longValue() != sysRole.getRoleId().longValue()))
			return ResultConstants.UPDATE_FAILED_NAME_IS_EXIST;

		sysRoleTemp = sysRoleDAO.findById(sysRole.getRoleId());

		if (null == sysRoleTemp)
			return ResultConstants.UPDATE_RECORD_NOT_EXIST;

		// 先删除角色权限关联信息
		List<SysRolePermission> menuIdList = sysRolePermissionDAO.findByProperty("sysRole.roleId", sysRoleTemp.getRoleId());
		// sysRoleTemp.getSysRolePermissions();
		// sysRoleTemp.setSysRolePermissions(null);
		if ((menuIdList != null) && (!menuIdList.isEmpty()))
		{
			sysRolePermissionDAO.deleteAll(menuIdList);
		}

		// 保存角色权限关联信息
		this.saveRoleMenu(sysRole.getPermissionIds(), sysRoleTemp);

		// 更新角色信息
		sysRoleTemp.setRoleDesc(sysRole.getRoleDesc());
		sysRoleTemp.setRoleName(sysRole.getRoleName());
		sysRoleTemp.setStatus(sysRole.getStatus());
		
		LoginToken loginToken = WebContextHolder.getCurrLoginToken();
		if (loginToken.getLoginInfo().getSystemId() == 0)
		{
			sysRoleTemp.setSystemId(sysRole.getSystemId());
		}
		
		sysRoleDAO.update(sysRoleTemp);

		return ResultConstants.UPDATE_SUCCEED;
	}

	/**
	 * 保存角色权限关联信息
	 * 
	 * @param menuIds
	 *            　权限ID，以逗号分隔
	 * @param sysRole
	 *            角色信息
	 */
	private void saveRoleMenu(String menuIds, SysRole sysRole)
	{

		// 批量保存角色权限关联信息
		String[] menuIdArr = menuIds.split(CommonConstants.SPLIT_SYMBOL_COMMA);
		Map<String, String> actions = new HashMap<String, String>();
		for (String menuId : menuIdArr)
		{
			if (menuId.contains("_"))
			{
				String[] tmps = menuId.split("_");
				if (actions.containsKey(tmps[0]))
				{
					// actions.put(tmps[0],
					// Permission.Actions.mergeActions(actions.get(tmps[0]),
					// tmps[1]));
				}
				else
					actions.put(tmps[0], tmps[1]);
			}
		}

		List<SysRolePermission> roleMenuList = new ArrayList<SysRolePermission>();
		for (String menuId : menuIdArr)
		{
			if (!menuId.contains("_"))
			{
				SysRolePermission rolePermission = new SysRolePermission();
				rolePermission.setSysRole(sysRole);
				rolePermission.setSysPermission(new SysPermission(Long.valueOf(menuId)));
				rolePermission.setPrivilege(actions.get(menuId));
				roleMenuList.add(rolePermission);
			}
		}
		sysRolePermissionDAO.saveAll(roleMenuList);
	}

	/**
	 * 根据单位ID查询角色信息
	 * 
	 * @param corpId
	 *            　单位ID
	 * @param status
	 *            　角色有效标志位
	 * 
	 * 
	 * @return　角色信息集合
	 * @throws Exception
	 */
	@Override
	public List<SysRole> findByCorpId(Long corpId) throws Exception
	{
		List<PropertyFilter> filterList = new ArrayList<PropertyFilter>();
		filterList.add(new PropertyFilter("corpId", MatchType.EQ, corpId));
		filterList.add(new PropertyFilter("status", MatchType.EQ, CommonConstants.STATUS_VALID));
		return sysRoleDAO.findByFilters(filterList);
	}

	@Autowired
	@Override
	@Qualifier(value = "sysRoleDAO")
	public void setBaseDao(BaseHibernateDAO<SysRole, Long> baseDao)
	{
		this.baseDao = baseDao;

	}

	@Override
	public List<SysRole> findBelowRoles() throws Exception
	{
		SysLogin sysLogin = this.getLoginToken().getLoginInfo();

		List<PropertyFilter> filters = new ArrayList<PropertyFilter>();
		if (sysLogin.getUserType().longValue() != SysLogin.USER_TYPE_SUPER_ADMIN)
		{
			List<SysLoginRole> sysLoginRoles = sysLoginRoleDAO.findByProperty("sysLogin.loginId", sysLogin.getLoginId());
			if (sysLoginRoles != null)
			{
				int order = Integer.MAX_VALUE;
				for (SysLoginRole sysLoginRole : sysLoginRoles)
				{
					if (sysLoginRole.getSysRole().getOrder() <= order)
						order = sysLoginRole.getSysRole().getOrder();
				}
				filters.add(new PropertyFilter("order", MatchType.GE, order));
			}
		}

		if (this.getLoginToken().getLoginInfo().getSystemId() != 0)
		{
			filters.add(new PropertyFilter("systemId", MatchType.EQ, this.getLoginToken().getLoginInfo().getSystemId()));
		}
		
		return baseDao.findByFilters(filters, Order.asc("order"));
	}

	@Override
	@Transactional(readOnly = false, rollbackFor = Throwable.class)
	public void changeOrder(Long id1, Long id2) throws Exception
	{
		SysRole role1 = baseDao.findById(id1);
		SysRole role2 = baseDao.findById(id2);

		if (null != role1 && null != role2)
		{
			Integer tmp = role1.getOrder();
			role1.setOrder(role2.getOrder());
			role2.setOrder(tmp);

			baseDao.update(role1);
			baseDao.update(role2);
		}

	}

	@Override
	public List<SysRole> findAllRole() throws Exception
	{
		List<SysRole> list = baseDao.findByHql("select roleName from SysRole ");
		return list;
	}

	@Override
	public SysRole getRoleId(String roleName) throws Exception
	{
		List<SysRole> list = baseDao.findByHql("from SysRole where roleName='" + roleName + "'");
		return list.get(0);
	}

}
